using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Linq;
using System.Windows.Forms;
using System.IO;

public interface BrowserListViewParent { }

public interface MyContextMenuStripParent
{
    void extract(object sender, EventArgs e);
}

[System.ComponentModel.DesignerCategory("Code")]
public class BrowserControl : UserControl, BrowserListViewParent, MyContextMenuStripParent
{
    private MyDirectoryInfo pwd2;
    public ListViewItem up2;
    public List<FileSystemInfo> entries;
    private BrowserState state;
    public Archive parItFile;
    MyContextMenuStrip contextMenu;
    BrowserListView listView1;
    ImageList icons;
    IContainer components = null;
    public event EventHandler ExtractClicked;

    public void extract(object sender, EventArgs e)
    {
        ExtractClicked(this, e);
    }

    private class MyContextMenuStrip : ContextMenuStrip
    {
        public ToolStripMenuItem extractItem;
        MyContextMenuStripParent parent;

        public MyContextMenuStrip(MyContextMenuStripParent parent)
        {
            this.parent = parent;
            extractItem = new ToolStripMenuItem();
            extractItem.Name = "extract";
            extractItem.Size = new Size(152, 22);
            extractItem.Text = "Extract";
            extractItem.Click += new EventHandler(parent.extract);
            Items.AddRange(new ToolStripItem[] { extractItem });
            Name = "contextMenuStrip1";
            Size = new Size(110, 26);
        }
    }

    private class BrowserListView : ListView
    {
        BrowserListViewParent parent;
        ColumnHeader columnName;
        ColumnHeader columnSize;
        ColumnHeader columnHeader3;
        ColumnHeader md5sum;

        public BrowserListView(BrowserListViewParent parent)
        {
            this.parent = parent;
            Dock = DockStyle.Fill;
            columnName = new ColumnHeader();
            columnSize = new ColumnHeader();
            columnHeader3 = new ColumnHeader();
            md5sum = new ColumnHeader();
            columnName.Text = "Name";
            columnName.Width = 206;
            columnSize.Text = "Size";
            columnHeader3.Text = "Compressed Size";
            md5sum.Text = "MD5Sum";
            md5sum.Width = 300;
            columnSize.Width = 100;
            columnHeader3.Width = 100;
            Columns.AddRange(new ColumnHeader[] { columnName, columnSize, columnHeader3, md5sum });
            TabIndex = 0;
            UseCompatibleStateImageBehavior = false;
            View = View.Details;
        }
    }

    public BrowserControl()
    {
        pwd2 = new MyDirectoryInfo();
        contextMenu = new MyContextMenuStrip(this);
        contextMenu.SuspendLayout();
        components = new Container();
        ComponentResourceManager resources = new ComponentResourceManager(typeof(BrowserControl));
        listView1 = new BrowserListView(this);
        listView1.Location = new System.Drawing.Point(0, 0);
        listView1.Name = "listView1";
        listView1.ItemActivate += new EventHandler(listView1_ItemActivate);
        listView1.ContextMenuStrip = contextMenu;
        icons = new ImageList(this.components);
        icons.ImageStream = ((ImageListStreamer)(resources.GetObject("icons.ImageStream")));
        icons.TransparentColor = Color.Transparent;
        icons.Images.SetKeyName(0, "folder.ico");
        icons.Images.SetKeyName(1, "file.ico");
        icons.Images.SetKeyName(2, "prtfile.ico");
        listView1.SmallImageList = this.icons;
        SuspendLayout();
        AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
        AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        Controls.Add(listView1);
        contextMenu.ResumeLayout(false);
        ResumeLayout(false);
        state = new DirectoryState(this);
        up2 = new ListViewItem();
        up2.Text = "..";
        up2.ImageIndex = 0;
        listView1.Items.Add(up2);
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
            components.Dispose();

        base.Dispose(disposing);
    }

    public BrowserState getState()
    {
        return state;
    }

    public ListView getListView()
    {
        return listView1;
    }

    public MyList getSelectedFiles()
    {
        MyList foo = new MyList();

        foreach (ListViewItem item in listView1.SelectedItems)
            foo.Add(entries[item.Index - 1]);

        return foo;
    }

    public void up()
    {
        pwd2.up();
        refresh();
    }

    public void changeState(BrowserState state)
    {
        this.state = state;
        refresh();
    }

    public DirectoryInfo chdir(DirectoryInfo dir)
    {
        DirectoryInfo foo = pwd2.chdir(dir);
        refresh();
        return foo;
    }

    public DirectoryInfo chdir(string dir) { return chdir(new DirectoryInfo(dir)); }
    public MyDirectoryInfo getPWD() { return pwd2; }

    public void refresh()
    {
        entries = pwd2.dir.EnumerateFileSystemInfos().ToList();
        state.refresh();
    }

    private void listView1_ItemActivate(object sender, EventArgs e)
    {
        state.activate();
    }
}

public abstract class BrowserState
{
    public BrowserState(BrowserControl context)
    {
        this.context = context;
    }

    public abstract void refresh();
    public abstract void activate();
    protected BrowserControl context;
}

public class ParItState : BrowserState
{
    public ParItState(BrowserControl context, Archive parItFile)
        : base(context)
    {
        context.parItFile = parItFile;
    }

    public override void refresh()
    {
        context.getListView().Items.Clear();
        context.getListView().Items.Add(context.up2);
        Iterator it = context.parItFile.getIterator();

        while (it.hasNext())
            context.getListView().Items.Add(it.next().toListViewItem());

        context.parItFile.count = it.count;
        it.reset();
    }

    public override void activate()
    {
        if (context.getListView().SelectedItems[0].Index == 0)
        {
            context.parItFile.reader.Close();
            context.parItFile = null;
            context.changeState(new DirectoryState(context));
        }
    }
}

public class DirectoryState : BrowserState
{
    public DirectoryState(BrowserControl context)
        : base(context)
    {
    }

    public override void refresh()
    {
        context.getListView().Items.Clear();
        context.getListView().Items.Add(context.up2);

        foreach (FileSystemInfo entry in context.entries)
        {
            ListViewItem item = new ListViewItem();

            if (entry.GetType().Equals(typeof(DirectoryInfo)))
            {
                item.ImageIndex = 0;
            }
            else if (entry.GetType().Equals(typeof(FileInfo)) && entry.Name.EndsWith(".prt"))
            {
                item.ImageIndex = 2;
            }
            else if (entry.GetType().Equals(typeof(FileInfo)))
            {
                item.ImageIndex = 1;
            }

            item.Text = entry.Name;

            if (entry.GetType().Equals(typeof(FileInfo)))
            {
                item.SubItems.Add(((FileInfo)(entry)).Length.ToString());   // nasty
            }

            context.getListView().Items.Add(item);
        }
    }

    public override void activate()
    {
        ListViewItem eersteSelectie = context.getListView().SelectedItems[0];

        if (eersteSelectie.Index == 0)
        {
            context.up();
        }
        else
        {
            int index = eersteSelectie.Index - 1;
            FileSystemInfo entry = context.entries[index];
            Type fileOrFolder = entry.GetType();

            if (fileOrFolder.Equals(typeof(DirectoryInfo)))
            {
                context.chdir(entry.FullName);
                context.refresh();
            }
            else if (fileOrFolder.Equals(typeof(FileInfo)) && entry.Name.EndsWith(".prt"))
            {
                ArchiveFactory factory = new ArchiveFactory();
                context.changeState(new ParItState(context, factory.load(entry.FullName)));
            }
        }
    }
}






